package com.ikingtech.platform.service.application.controller;

import com.ikingtech.framework.sdk.application.api.ApplicationMenuApi;
import com.ikingtech.framework.sdk.application.api.ApplicationPageApi;
import com.ikingtech.framework.sdk.application.model.ApplicationPageDTO;
import com.ikingtech.framework.sdk.application.model.ApplicationPageModelDTO;
import com.ikingtech.framework.sdk.application.model.ApplicationPageQueryParamDTO;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.enums.application.ApplicationPageTypeEnum;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.ApiController;
import com.ikingtech.platform.service.application.entity.ApplicationPageDO;
import com.ikingtech.platform.service.application.entity.ApplicationPageModelDO;
import com.ikingtech.platform.service.application.service.ApplicationPageModelService;
import com.ikingtech.platform.service.application.service.ApplicationPageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author tie yan
 */
@Slf4j
@RequiredArgsConstructor
@ApiController(value = "/application/page", name = "应用中心-页面管理", description = "应用中心-页面管理")
public class ApplicationPageController implements ApplicationPageApi {

    private final ApplicationPageService service;

    private final ApplicationPageModelService pageModelService;

    private final ApplicationMenuApi applicationMenuApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<ApplicationPageDTO> add(ApplicationPageDTO page) {
        ApplicationPageDO entity = Tools.Bean.copy(page, ApplicationPageDO.class);
        entity.setId(Tools.Id.uuid());
        if (!ApplicationPageTypeEnum.BUSINESS.name().equals(entity.getType())) {
            entity.setLink(Tools.Str.format("/vpage-render/{}", entity.getId()));
            entity.setComponent("function-design/auto-rander/index.vue");
        }
        this.service.save(entity);
        this.insertPageModel(entity.getId(), page.getModelIds());
        this.savePageMenu(entity);
        return R.ok(this.modelConvert(entity));
    }

    @Override
    public R<Object> delete(String id) {
        ApplicationPageDO entity = this.service.getById(id);
        if (null == entity) {
            throw new FrameworkException("appPageNotFound");
        }
        this.service.removeById(id);
        this.applicationMenuApi.removeByPermissionCode(id, "APP_PREVIEW", entity.getAppCode());
        return R.ok();
    }

    @Override
    public R<Object> update(ApplicationPageDTO page) {
        if (!this.service.exist(page.getId())) {
            throw new FrameworkException("appPageNotFound");
        }
        ApplicationPageDO entity = Tools.Bean.copy(page, ApplicationPageDO.class);
        this.service.updateById(entity);
        this.savePageMenu(entity);
        this.updatePageModel(entity.getId(), page.getModelIds());
        return R.ok();
    }

    @Override
    public R<List<ApplicationPageDTO>> page(ApplicationPageQueryParamDTO queryParam) {
        return R.ok(this.service.listPage(queryParam).convertBatch(this::modelConvert));
    }

    @Override
    public R<List<ApplicationPageDTO>> all() {
        return R.ok(this.modelConvert(this.service.list()));
    }

    @Override
    public R<ApplicationPageDTO> detail(String id) {
        ApplicationPageDO entity = this.service.getById(id);
        if (null == entity) {
            throw new FrameworkException("appPageNotFound");
        }
        return R.ok(this.modelConvert(this.service.getById(id)));
    }

    @Override
    public R<List<ApplicationPageDTO>> listByAppId(String appId) {
        return R.ok(this.modelConvert(this.service.listByAppId(appId)));
    }

    private void insertPageModel(String pageId, List<String> modelIds) {
        if (Tools.Coll.isNotBlank(modelIds)) {
            this.pageModelService.saveBatch(Tools.Coll.convertList(modelIds, modelId -> {
                ApplicationPageModelDO pageModeEntity = new ApplicationPageModelDO();
                pageModeEntity.setId(Tools.Id.uuid());
                pageModeEntity.setPageId(pageId);
                pageModeEntity.setModelId(modelId);
                return pageModeEntity;
            }));
        }
    }

    private void updatePageModel(String pageId, List<String> modelIds) {
        this.pageModelService.removeByPageId(pageId);
        this.insertPageModel(pageId, modelIds);
    }

    private List<ApplicationPageDTO> modelConvert(List<ApplicationPageDO> entities) {
        return Tools.Coll.convertList(entities, this::modelConvert);
    }

    private ApplicationPageDTO modelConvert(ApplicationPageDO entity) {
        ApplicationPageDTO page = Tools.Bean.copy(entity, ApplicationPageDTO.class);
        if (null != page.getType()) {
            page.setTypeName(page.getType().description);
        }
        List<ApplicationPageModelDO> pageModelEntities = this.pageModelService.listByPageId(page.getId());
        page.setModelIds(Tools.Coll.convertList(pageModelEntities, ApplicationPageModelDO::getModelId));
        page.setModels(Tools.Coll.convertList(pageModelEntities, pageModelEntity -> Tools.Bean.copy(pageModelEntity, ApplicationPageModelDTO.class)));
        return page;
    }

    private void savePageMenu(ApplicationPageDO entity) {
        if (ApplicationPageTypeEnum.GROUP.name().equals(entity.getType())) {
            this.applicationMenuApi.saveOrUpdate(entity.getId(),
                    entity.getName(),
                    entity.getParentId(),
                    entity.getIcon(),
                    Tools.Str.EMPTY,
                    Tools.Str.EMPTY,
                    "APP_PREVIEW",
                    entity.getAppCode());
        } else {
            this.applicationMenuApi.saveOrUpdate(entity.getId(),
                    entity.getName(),
                    entity.getParentId(),
                    entity.getIcon(),
                    entity.getLink(),
                    entity.getComponent(),
                    "APP_PREVIEW",
                    entity.getAppCode());
        }
    }
}
